#include "OcroIze.hpp"

#include <colib/colib.h>
#include <iulib/iulib.h>
#include <ocropus/ocropus.h>
#include <ocropus/glinerec.h>
#include <iostream>

using namespace iulib;
using namespace colib;
using namespace ocropus;
using namespace narray_ops;
using namespace glinerec;
using namespace std;

#define DEFAULT_DATA_DIR "/usr/local/share/ocropus/models/"
#define LOAD_OBSOLETE_FORMATS_OPTIONALLY 0

extern void linerec_load(autodel<IRecognizeLine> &,const char *);


void linerec_load(autodel<IRecognizeLine> &linerec,const char *cmodel) {
#if LOAD_OBSOLETE_FORMATS_OPTIONALLY
    linerec = glinerec::make_Linerec();
    try {
        load_component(stdio(cmodel,"r"),linerec);
    } catch(...) {
        debugf("debug","%s: failed to load as component, trying as object\n",cmodel);
        try {
            linerec->load(cmodel);
        } catch(const char *s) {
            throwf("%s: failed to load (%s)",(const char*)cmodel,s);
        } catch(...) {
            throwf("%s: failed to load character model",(const char*)cmodel);
        }
    }
#else
    load_component(stdio(cmodel,"r"),linerec);
#endif
}

OcroIze::OcroIze()
{
}


std::string OcroIze::run(const std::string &filename)
{
    std::string out;

    init_ocropus_components();
    init_glclass();
    init_glfmaps();
    init_linerec();

    param_int beam_width("beam_width", 100, "number of nodes in a beam generation");
    param_string csegmenter("csegmenter","SegmentPageByRAST","page segmentation component");
    param_string cmodel("cmodel",DEFAULT_DATA_DIR"/default.model","character model used for recognition");
    param_string lmodel("lmodel",DEFAULT_DATA_DIR"/default.fst","language model used for recognition");
    // create the segmenter
    autodel<ISegmentPage> segmenter;
    make_component(segmenter,csegmenter);
    // load the line recognizer
    autodel<IRecognizeLine> linerec;
    linerec_load(linerec,cmodel);
    // load the language model
    autodel<OcroFST> langmod;
    if(lmodel && strcmp(lmodel,"")) {
        langmod = make_OcroFST();
        try {
            langmod->load(lmodel);
        } catch(const char *s) {
            throwf("%s: failed to load (%s)",(const char*)lmodel,s);
        } catch(...) {
            throwf("%s: failed to load language model",(const char*)lmodel);
        }
    }
    // now iterate through the pages

        Pages pages;
        pages.parseSpec(filename.c_str());
        if(pages.nextPage()){
            bytearray page_binary,page_gray;
            intarray page_seg;
            pages.getBinary(page_binary);
            pages.getGray(page_gray);
            segmenter->segment(page_seg,page_binary);
            RegionExtractor regions;
            regions.setPageLines(page_seg);
            for(int i=1;i<regions.length();i++) {
                try {
                    bytearray line_image;
                    regions.extract(line_image,page_gray,i,1);
                    autodel<OcroFST> result(make_OcroFST());
                    linerec->recognizeLine(*result,line_image);
                    ustrg str;
                    if(!langmod) {
                        result->bestpath(str);
                    } else {
                        double cost = beam_search(str,*result,*langmod,beam_width);
                        if(cost>1e10) throw "beam search failed";
                    }
                    utf8strg utf8Output;
                    str.utf8EncodeTerm(utf8Output);
                    const char *c = reinterpret_cast<const char*>(utf8Output.c_str());
                    out.append(c);
                } catch(const char *error) {
                    debugf("error","%s\n",error);
                }
            }
        }
        return out;
}
